package org.budo.jdbc.driver;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;

import org.budo.jdbc.driver.exception.BudoJdbcDriverNotSupportedException;

import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;

/**
 * @author li
 */
@Slf4j
@Getter
@Setter
@Accessors(chain = true)
public abstract class AbstractBudoJdbcStatement implements Statement {
    private Connection connection;

    private PreparedStatement prepareStatement;

    @Override
    public Connection getConnection() throws SQLException {
        return this.connection;
    }

    @Override
    public boolean execute(String sql) throws SQLException {
        this.prepareStatement = this.getConnection().prepareStatement(sql);
        return this.getPrepareStatement().execute();
    }

    @Override
    public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
        this.prepareStatement = this.connection().prepareStatement(sql, autoGeneratedKeys);
        return this.getPrepareStatement().execute();
    }

    protected Connection connection() throws SQLException {
        if (null != this.getConnection()) {
            return this.getConnection();
        }

        throw new RuntimeException("#51 no connection, this=" + this);
    }

    @Override
    public void close() throws SQLException {
        if (null != this.getPrepareStatement()) {
            this.getPrepareStatement().close();
        }

        if (null != this.getConnection()) {
            this.getConnection().close();
        }
    }

    @Override
    public ResultSet getResultSet() throws SQLException {
        return this.getPrepareStatement().getResultSet();
    }

    @Override
    public int getUpdateCount() throws SQLException {
        return this.getPrepareStatement().getUpdateCount();
    }

    @Override
    public ResultSet executeQuery(String sql) throws SQLException {
        this.execute(sql); // 允许执行更新语句

        return this.getResultSet();
    }

    @Override
    public int executeUpdate(String sql) throws SQLException {
        boolean hasResultSet = this.execute(sql);

        // 先执行再报错?
        if (hasResultSet) {
            throw new SQLException("#31 not write statement, do not use executeUpdate, sql=" + sql);
        }

        return this.getUpdateCount();
    }

    @Override
    public boolean isPoolable() throws SQLException {
        return true;
    }

    @Override
    public void setPoolable(boolean poolable) {
        if (!poolable) {
            throw new BudoJdbcDriverNotSupportedException("#90 why don't you want me to be poolable?");
        }
    }

    @Override
    public void setFetchSize(int fetchSize) throws SQLException {
        log.debug("#96 setFetchSize, fetchSize={}, this={}", fetchSize, this);
    }

    @Override
    public int getFetchSize() throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public boolean getMoreResults() throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public void setFetchDirection(int direction) throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public void setQueryTimeout(int seconds) throws SQLException {
        log.info("#103 setQueryTimeout this=" + this);
    }

    @Override
    public int getQueryTimeout() throws SQLException {
        return 0;
    }

    @Override
    public ResultSet getGeneratedKeys() throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public int getMaxFieldSize() throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public void setMaxFieldSize(int max) throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public int getMaxRows() throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public void setMaxRows(int max) throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public void setEscapeProcessing(boolean enable) throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public void cancel() throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public SQLWarning getWarnings() throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public void clearWarnings() throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public void setCursorName(String name) throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public int getFetchDirection() throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public int getResultSetConcurrency() throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public int getResultSetType() throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public void addBatch(String sql) throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public void clearBatch() throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public int[] executeBatch() throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public boolean getMoreResults(int current) throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public int executeUpdate(String sql, String[] columnNames) throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public boolean execute(String sql, int[] columnIndexes) throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public boolean execute(String sql, String[] columnNames) throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public int getResultSetHoldability() throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public boolean isClosed() throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public void closeOnCompletion() throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }

    @Override
    public boolean isCloseOnCompletion() throws SQLException {
        throw new BudoJdbcDriverNotSupportedException();
    }
}